import { Feature } from 'ol'
import { WKT } from 'ol/format'
import { LinearRing, LineString, Point, Polygon } from 'ol/geom'
import { Vector as VectorLayer } from 'ol/layer'
import { fromLonLat, transform } from 'ol/proj'
import { get as getProjection } from 'ol/proj.js'
import { transformExtent } from 'ol/proj.js'
import { Vector as VectorSource, Cluster } from 'ol/source'
import { Circle, Fill, Icon, Stroke, Style, Text } from 'ol/style'

//地图管理操作类
class MapOperation {
  map = null
  view = null
  layers = {}
  tileInfoWeb = {
    dpi: 96,
    rows: 256,
    cols: 256,
    compressionQuality: 0,
    origin: {
      x: -20037508.3427892,
      y: 20037508.3427892
    },
    spatialReference: {
      wkid: 3857
    },
    lods: [
      {
        level: 2,
        levelValue: 2,
        resolution: 39135.75848201024,
        scale: 147748796.52937502
      },
      {
        level: 3,
        levelValue: 3,
        resolution: 19567.87924100512,
        scale: 73874398.264687508
      },
      {
        level: 4,
        levelValue: 4,
        resolution: 9783.93962050256,
        scale: 36937199.132343754
      },
      {
        level: 5,
        levelValue: 5,
        resolution: 4891.96981025128,
        scale: 18468599.566171877
      },
      {
        level: 6,
        levelValue: 6,
        resolution: 2445.98490512564,
        scale: 9234299.7830859385
      },
      {
        level: 7,
        levelValue: 7,
        resolution: 1222.99245256282,
        scale: 4617149.8915429693
      },
      {
        level: 8,
        levelValue: 8,
        resolution: 611.49622628141,
        scale: 2308574.9457714846
      },
      {
        level: 9,
        levelValue: 9,
        resolution: 305.748113140705,
        scale: 1154287.4728857423
      },
      {
        level: 10,
        levelValue: 10,
        resolution: 152.8740565703525,
        scale: 577143.73644287116
      },
      {
        level: 11,
        levelValue: 11,
        resolution: 76.43702828517625,
        scale: 288571.86822143558
      },
      {
        level: 12,
        levelValue: 12,
        resolution: 38.21851414258813,
        scale: 144285.93411071779
      },
      {
        level: 13,
        levelValue: 13,
        resolution: 19.109257071294063,
        scale: 72142.967055358895
      },
      {
        level: 14,
        levelValue: 14,
        resolution: 9.554628535647032,
        scale: 36071.483527679447
      },
      {
        level: 15,
        levelValue: 15,
        resolution: 4.777314267823516,
        scale: 18035.741763839724
      },
      {
        level: 16,
        levelValue: 16,
        resolution: 2.388657133911758,
        scale: 9017.8708819198619
      },
      {
        level: 17,
        levelValue: 17,
        resolution: 1.194328566955879,
        scale: 4508.9354409599309
      },
      {
        level: 18,
        levelValue: 18,
        resolution: 0.5971642834779395,
        scale: 2254.4677204799655
      }
      // { level: 19, levelValue: 19, resolution: 0.298582141738970, scale: 1127.23386023998275 },
      // { level: 20, levelValue: 20, resolution: 0.298582141738970 / 2, scale: 1127.23386023998275 / 2 }
      // { level: 21, levelValue: 21, resolution: 0.298582141738970 / 4, scale: 1127.23386023998275 / 4 }
    ]
  }

  constructor(map, view, layers) {
    this.map = map
    this.view = map.getView()
    this.layers = layers
  }
  //添加业务图层
  addLayer(ywlx) {
    if (!this.layers[ywlx]) {
      this.layers[ywlx] = new BusinessLayer(this.map, ywlx)
    }
  }
  xsywLayer(ywlx) {
    // this.layers[ywlx].layers['TC'].values_.visible = true
    for (let key in this.layers[ywlx].layers) {
      // key 是属性名，obj[key] 是对应的值
      this.layers[ywlx].layers[key].values_.visible = true
    }
  }
  // 辖区定位
  jurisdiction(minx, maxx, miny, maxy) {
    // 创建四至范围
    const extent = transformExtent(
      [minx, miny, maxx, maxy], // 最小经度、最小纬度、最大经度、最大纬度
      'EPSG:4326',
      'EPSG:3857' // 将 WGS84 坐标系转换为 Web Mercator 投影坐标系
    )

    // 定位到四至范围
    this.view.fit(extent, { padding: [10, 10, 10, 10] })
  }
  ycywLayer(ywlx) {
    for (let key in this.layers[ywlx].layers) {
      // key 是属性名，obj[key] 是对应的值
      this.layers[ywlx].layers[key].values_.visible = false
    }
  }
  moveMap(move, zoom) {
    if (zoom) {
      this.view.setZoom(zoom)
    }
    this.view.setCenter(move)
  }
  //删除业务图层
  removeLayer(ywlx) {
    this.layers[ywlx].removeLayer()
  }
  /**
   *  * 添加feature到对应图层
   * @param {业务类型} ywlx
   * @param {} feature
   * @param {图层名称} target
   **/
  addFeatureTo(ywlx, feature, target, zIndex) {
    this.addLayer(ywlx)
    this.layers[ywlx].addFeatureTo(feature, target, zIndex)
  }
  createFeatureToByRings(rings, target, id, tbStylet) {
    let feature
    let type = 0
    if (rings.rings) {
      type = 2
      feature = new Feature({
        geometry: new Polygon(rings.rings)
      })
    } else if (rings.paths) {
      type = 1
      feature = new Feature({
        geometry: new LineString(rings.paths[0])
      })
    } else if (rings.x && rings.y) {
      type = 0
      feature = new Feature({
        geometry: new Point(fromLonLat([rings.x, rings.y]))
      })
    }
    // 判断 tbStylet 是否存在
    // console.log(feature, 'feature');
    let pointFill = new Fill({
      color: type !== 0 ? 'rgba(255, 255, 255, 0.2)' : 'rgba(255, 255, 255, 1)'
    })
    let pointStroke = new Stroke({
      color: 'yellow',
      width: 5
    })
    if (tbStylet) {
      pointStroke = new Stroke({
        color: tbStylet.tbColor ? tbStylet.tbColor : 'yellow',
        // width: tbStylet.tbColor == 'red' ? 1 : 3,
        width: tbStylet?.tbWidth ? tbStylet.tbWidth : 1
      })
      feature.setStyle(
        new Style({
          fill: pointFill,
          stroke: pointStroke,
          image: new Circle({
            //此处因为上图是点位是画了个圆所以设置颜色
            fill: pointFill,
            stroke: pointStroke,
            radius: tbStylet?.tbWidth ? (tbStylet.tbWidth > 5 ? tbStylet.tbWidth : 5) : 5
          }),
          text: new Text({
            font: 'normal 14px 黑体',
            // // 对其方式
            textAlign: 'center',
            // 基准线
            textBaseline: 'bottom',
            // 文本填充样式
            fill: new Fill({
              color: tbStylet.tbColor ? tbStylet.tbColor : 'yellow'
            }),
            overflow: true,
            padding: [5, 5, 5, 5],
            text: `${tbStylet.text || ''}`
          })
        })
      )
    } else {
      // 默认
      feature.setStyle(
        new Style({
          fill: pointFill,
          stroke: pointStroke,
          image: new Circle({
            //此处因为上图是点位是画了个圆所以设置颜色
            fill: pointFill,
            stroke: pointStroke,
            radius: tbStylet?.tbWidth ? tbStylet.tbWidth : 1
          })
        })
      )
    }

    if (id) {
      feature.setId(id)
    }
    feature.set('layername', target)
    if (rings.rings || rings.paths) {
      let crs = getProjection('EPSG:4326')
      let geom = feature.getGeometry().transform(crs, this.view.getProjection())
      feature.setGeometry(geom)
    }
    return feature
  }
  addFeatureToByRings(ywlx, rings, target, id, tbStylet, zIndex) {
    let target_new = target || 'TB'
    let feature = this.createFeatureToByRings(rings, target, id, tbStylet)
    this.addFeatureTo(ywlx, feature, target_new, zIndex)
    return feature
  }
  addPoint(ywlx, target, coordinate, rotation = 0, id, src, scale = 1) {
    let feature = new Feature({
      geometry: new Point(fromLonLat(coordinate))
    })
    feature.setStyle(
      new Style({
        image: new Icon({
          src: src,
          scale: scale,
          rotation: (3.14 / 180) * rotation
        })
      })
    )
    feature.setId(id)
    this.addFeatureTo(ywlx, feature, target)
  }

  // 创建聚合图层
  createCluster({ distance, minDistance, features, count = 0 }) {
    // 聚合类
    let cluster = new Cluster({
      distance: distance || 80,
      minDistance: minDistance || 0,
      source: new VectorSource({
        features: features
      })
    })
    // 聚合图层
    let clusterLayer = new VectorLayer({
      source: cluster,
      minZoom: 1,
      zIndex: 9,
      style: feature => {
        if (!feature.get('features')) {
          return null
        } else {
          let featureArr = feature.get('features')
          let text = count == 0 ? featureArr.length.toString() : count.length.toString()
          return new Style({
            image: new Circle({
              radius: 20,
              stroke: new Stroke({
                color: '#fff'
              }),
              fill: new Fill({
                color: '#3399CC'
              })
            }),
            text: new Text({
              text: text,
              fill: new Fill({
                color: '#fff'
              })
            })
          })
        }
      }
    })

    return clusterLayer
  }

  //清除矢量
  clear(ywlx, target) {
    if (this.layers[ywlx]) this.layers[ywlx].clear(target)
  }
  //通过id清除对应层矢量
  removeFeatureById(ywlx, target, id) {
    if (this.layers[ywlx]) this.layers[ywlx].removeFeatureById(target, id)
  }
  // 通过Id获取对应的feature
  getFeatureById(ywlx, target, id) {
    return this.layers[ywlx].getFeatureById(target, id)
  }
  getFeatures(ywlx, target) {
    return this.layers[ywlx].getFeatures(target)
  }
  setLayerVisibility(ywlx, visible, target) {
    if (this.layers[ywlx]) this.layers[ywlx].setLayerVisibility(visible, target)
  }
  zoomToGeometry(geometry, options) {
    // let transGeometry = null
    // if(geometry.getType() !== 'Point'){
    //     let crs = getProjection("EPSG:4326");
    //     transGeometry = geometry.transform(crs, this.view.getProjection());
    //     feature.setGeometry(geom);
    // }else{
    //     let coordinates = fromLonLat(geometry.getCoordinates(),this.view.getProjection());
    //     transGeometry = new Point(coordinates)
    // }
    this.view.fit(geometry, options)
  }
  getFeatureByWKT(wkt) {
    try {
      if (!wkt) {
        return null
      }
      // 数据格式类型
      let format = new WKT()

      let feature
      let crs = getProjection('EPSG:4326')
      feature = format.readFeature(wkt, {
        featureProjection: this.view.getProjection(),
        dataProjection: crs
      })

      return feature
    } catch (e) {
      console.log(e)
      return null
    }
  }
  changeRingsToWkt(rings) {
    let feature = null
    if (rings.rings) {
      feature = new Feature({
        geometry: new Polygon(rings.rings)
      })
    } else if (rings.paths) {
      feature = new Feature({
        geometry: new LinearRing(rings.paths[0])
      })
    }
    let format = new WKT()
    return format.writeFeature(feature)
  }

  changeWktToRings(wkt) {}

  getRingsByFeature(feature) {
    const geom = feature.getGeometry()
    let output = {}
    let coordinates = geom.getCoordinates()
    if (geom instanceof Polygon || geom instanceof LineString) {
      let crs = getProjection('EPSG:4326')
      let geom = feature.getGeometry().transform(this.view.getProjection(), crs)
      if (geom instanceof Polygon) {
        output.rings = coordinates
      }
      if (geom instanceof LineString) {
        output.paths = [coordinates]
      }
    } else {
      let points = fromLonLat([coordinates[0], coordinates[1]])
      output = {
        x: points[0],
        y: points[1]
      }
    }
    return output
  }

  getRingsByFeatureNoTransform(feature) {
    const geom = feature.getGeometry()
    let output = {}
    let coordinates = geom.getCoordinates()
    if (geom instanceof Polygon) {
      output.rings = coordinates
    } else if (geom instanceof LineString) {
      output.paths = [coordinates]
    } else if (geom instanceof Point) {
      output = {
        x: coordinates[0],
        y: coordinates[1]
      }
    }
    return output
  }
  createTextStyle(text) {
    return new Style({
      text: new Text({
        text: text + '',
        overflow: true, // 允许文本溢出
        textAlign: 'center',
        offsetX: -5,
        offsetY: -21,
        fill: new Fill({
          color: '#FFF'
        }),
        font: '20px Arial', // 默认字体样式
        backgroundFill: new Fill({
          color: '#2379ff'
        }),
        backgroundStroke: new Stroke({
          // 添加边框样式
          color: '#2379ff',
          lineJoin: 'round',
          width: 8
        }),
        padding: [6, 8, 3, 10]
      })
    })
  }
  // lonLat经纬度，isTransform是否转换
  createPointFeature(lonLat, isTransform) {
    if (isTransform) {
      return new Feature({
        geometry: new Point(transform(lonLat, 'EPSG:4326', 'EPSG:3857'))
      })
    } else {
      return new Feature({
        geometry: new Point(lonLat)
      })
    }
  }
  // 根据feature创建layer
  createLayerByFeatures(features, style) {
    let layer = new VectorLayer({
      source: new VectorSource({
        features: features
      })
    })
    if (style) {
      layer.setStyle(style)
    }
    return layer
  }
  // 设置图形样式，返回样式实例
  /**
   *
   * @param {Object} color
   * @returns
   */
  getPolygonStyle(color) {
    let colorObj = {
      strokeColor: 'rgba(51, 136, 255)',
      strokeWidth: 3,
      fillColor: 'rgba(51, 136, 255, 0.3)',
      ...color
    }
    return new Style({
      stroke: new Stroke({
        color: colorObj.strokeColor,
        width: colorObj.strokeWidth
      }),
      fill: new Fill({
        color: colorObj.fillColor
      })
    })
  }
  addFeature(rings, style) {
    let wgfeature = new Feature({
      geometry: new Polygon(rings)
    })
    if (style) {
      wgfeature.setStyle(style)
    }
    let crs = getProjection('EPSG:4326')
    let geom = wgfeature.getGeometry().transform(crs, this.view.getProjection())
    wgfeature.setGeometry(geom)
    return wgfeature
  }

  // transform4326 是否需要转换成4326
  //获取视图窗口四至范围
  getViewExtent(transform4326) {
    let size = this.map.getSize()
    let calculateExtent = this.map.getView().calculateExtent(size)

    if (transform4326) {
      calculateExtent = transformExtent(calculateExtent, 'EPSG:3857', 'EPSG:4326')
    }
    let extent = {
      xmax: calculateExtent[2],
      xmin: calculateExtent[0],
      ymax: calculateExtent[3],
      ymin: calculateExtent[1]
    }
    return extent
  }

  // transform4326 是否转换为4326
  getTielsByExtent(extent, transform4326) {
    let resolution = this.map.getView().getResolution()
    let tileInfoWeb = this.tileInfoWeb
    // 获取最近层
    let lodNearest = null
    for (let i = 0; i < tileInfoWeb.lods.length - 1; i++) {
      const lod0 = tileInfoWeb.lods[i]
      const lod1 = tileInfoWeb.lods[i + 1]
      if (lod0.resolution <= resolution) {
        lodNearest = lod0
        break
      } else if (lod0.resolution > resolution && lod1.resolution <= resolution) {
        lodNearest = lod0
        break
      } else if (i === tileInfoWeb.lods.length - 2) {
        // 如果已经是最后一个了还不满足，那就给最后一个
        lodNearest = lod1
        break
      }
    }
    // 获取左上角所在瓦片的行列号
    let leftTop = this.getTielsRowColum(extent.xmin, extent.ymax, tileInfoWeb.origin, lodNearest, tileInfoWeb.rows)
    let rightBottom = this.getTielsRowColum(extent.xmax, extent.ymin, tileInfoWeb.origin, lodNearest, tileInfoWeb.rows)
    // 从左往右，从上往下开始拼接数组
    let arrayExtent = []
    let widthl = tileInfoWeb.rows * lodNearest.resolution // 每行的宽度
    for (let row = leftTop.row; row <= rightBottom.row; row++) {
      for (let col = leftTop.colum; col <= rightBottom.colum; col++) {
        // 当前行列的左下右上坐标
        let envelop = {
          type: 'extent',
          spatialReference: { wkid: 3857 },
          xmin: tileInfoWeb.origin.x + widthl * col,
          xmax: tileInfoWeb.origin.x + widthl * col + widthl,
          ymin: tileInfoWeb.origin.y - widthl * row - widthl,
          ymax: tileInfoWeb.origin.y - widthl * row
        }

        // 转换成4326格式的
        if (transform4326) {
          let extent3857 = [envelop.xmin, envelop.ymin, envelop.xmax, envelop.ymax]
          let extent4326 = transformExtent(extent3857, 'EPSG:3857', 'EPSG:4326')
          envelop.xmin = extent4326[0]
          envelop.ymin = extent4326[1]
          envelop.xmax = extent4326[2]
          envelop.ymax = extent4326[3]
          envelop.spatialReference = { wkid: 4326 }
        }
        arrayExtent.push(envelop)
      }
    }
    return {
      extents: arrayExtent,
      level: lodNearest.level,
      levelCount: tileInfoWeb.lods.length - 1
    }
  }

  getTielsRowColum(x, y, origin, lod, tilesize) {
    let widthl = tilesize * lod.resolution
    let startCol = Math.floor((x - origin.x) / widthl)
    let startRow = Math.floor((origin.y - y) / widthl)
    return { row: startRow, colum: startCol }
  }
}
//业务图层设计
class BusinessLayer {
  layers = {
    LOCATION: null,
    SHAPE: null,
    MON: null
  }
  constructor(map, ywlx) {
    this.map = map
    this.ywlx = ywlx
    for (let layerName in this.layers) {
      let zindex = layerName == 'LOCATION' ? 3 : layerName == 'MON' ? 2 : layerName == 'SHAPE' ? 1 : undefined
      this.layers[layerName] = new VectorLayer({
        source: new VectorSource(),
        properties: {
          ywlx: this.ywlx
        },
        minZoom: 4,
        zIndex: zindex
      })
      this.map.addLayer(this.layers[layerName])
    }
  }
  addFeatureTo(feature, target, zIndex) {
    if (!this.layers[target]) {
      this.layers[target] = new VectorLayer({
        source: new VectorSource(),
        properties: {
          ywlx: this.ywlx
        },
        zIndex: zIndex
      })
      this.map.addLayer(this.layers[target])
    }
    this.layers[target].getSource().addFeature(feature)
  }
  clear(target) {
    if (this.layers[target]) this.layers[target].getSource().clear()
  }
  //删除业务图层有问题。应该是移除
  removeLayer() {
    for (const iterator in this.layers) {
      this.layers[iterator].getSource().clear()
    }
  }
  removeFeatureById(target, id) {
    if (!this.layers[target]) return
    let layer = this.layers[target].getSource()
    if (layer.getFeatureById(id)) {
      layer.removeFeature(layer.getFeatureById(id))
    }
  }
  getFeatureById(target, id) {
    let layer = this.layers[target].getSource()
    return layer.getFeatureById(id)
  }
  getFeatures(target) {
    let layer = this.layers[target].getSource()
    return layer.getFeatures()
  }
  setLayerVisibility(visible, target) {
    if (target && this.layers[target]) {
      // 隐藏指定图层
      this.layers[target].setVisible(visible)
      return
    }
    for (const iterator in this.layers) {
      if (iterator) this.layers[iterator].setVisible(visible)
    }
  }
}

function changeRingsToWkt(rings) {
  let feature = null
  if (rings.rings) {
    feature = new Feature({
      geometry: new Polygon(rings.rings)
    })
  } else if (rings.paths) {
    feature = new Feature({
      geometry: new LinearRing(rings.paths[0])
    })
  }
  let format = new WKT()
  return format.writeFeature(feature)
}

let mapOperatio = null
export const getMapOperation = () => {
  return mapOperatio
}
export const setMapOperation = (map, view, layers) => {
  mapOperatio = new MapOperation(map, view, layers)
  return mapOperatio
}
//移除
let mapOperatio2 = null
export const setMapOperation2 = (map, view, layers) => {
  mapOperatio2 = new MapOperation(map, view, layers)
}
export const getMapOperation2 = () => {
  return mapOperatio2
}
export default MapOperation
export { changeRingsToWkt }
